package org.finesys.chat.core.base.embedding.store.pgvector.filter;

import java.util.AbstractMap;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.finesys.chat.core.base.embedding.filter.Filter;
import org.finesys.chat.core.base.embedding.filter.compairson.EqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.GreaterThanEqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.GreaterThanFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.InFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.LessThanEqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.LessThanFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.LikeFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.NotEqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.NotInFilter;
import org.finesys.chat.core.base.embedding.filter.logical.AndFilter;
import org.finesys.chat.core.base.embedding.filter.logical.NotFilter;
import org.finesys.chat.core.base.embedding.filter.logical.OrFilter;

public abstract class PgVectorFilterMapper {

    static final Map<Class<?>, String> SQL_TYPE_MAP =Stream.of(
        new AbstractMap.SimpleEntry<>(Integer.class, "integer"), 
        new AbstractMap.SimpleEntry<>(Long.class, "bigint"), 
        new AbstractMap.SimpleEntry<>(Float.class, "float"), 
        new AbstractMap.SimpleEntry<>(Double.class, "float8"), 
        new AbstractMap.SimpleEntry<>(String.class, "text"), 
        new AbstractMap.SimpleEntry<>(Object.class, "text"), 
        new AbstractMap.SimpleEntry<>(UUID.class, "uuid"), 
        new AbstractMap.SimpleEntry<>(Boolean.class, "boolean"))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

    public PgVectorFilterMapper() {
    }


    public String map(Filter filter) {
        if (filter instanceof EqualFilter) {
            return this.mapEqualFilter((EqualFilter) filter);
        } else if (filter instanceof NotEqualFilter) {
            return this.mapNotEqualFilter((NotEqualFilter) filter);
        } else if (filter instanceof GreaterThanFilter) {
            return this.mapGreaterThanFilter((GreaterThanFilter) filter);
        } else if (filter instanceof GreaterThanEqualFilter) {
            return this.mapGreaterThanEqualFilter((GreaterThanEqualFilter) filter);
        } else if (filter instanceof LessThanEqualFilter) {
            return this.mapLessThanEqualFilter((LessThanEqualFilter) filter);
        } else if (filter instanceof LessThanFilter) {
            return this.mapLessThanFilter((LessThanFilter) filter);
        } else if (filter instanceof LikeFilter) {
            return this.mapLikeFilter((LikeFilter) filter);
        } else if (filter instanceof InFilter) {
            return this.mapInFilter((InFilter) filter);
        } else if (filter instanceof NotInFilter) {
            return this.mapNotInFilter((NotInFilter) filter);
        } else if (filter instanceof AndFilter) {
            return this.mapAndFilter((AndFilter) filter);
        } else if (filter instanceof OrFilter) {
            return this.mapOrFilter((OrFilter) filter);
        } else if (filter instanceof NotFilter) {
            return this.mapNotFilter((NotFilter) filter);
        } else {
            throw new RuntimeException("不支持的过滤器类型");
        }
    }


    private String mapEqualFilter(EqualFilter filter) {
        String key = this.formatKey(filter.getKey(), filter.getCompairsonValue().getClass());
        return String.format("%s is not null and %s = %s", key, key, this.formatValue(filter.getCompairsonValue()));
    }

    private String mapNotEqualFilter(NotEqualFilter filter) {
        String key = this.formatKey(filter.getKey(), filter.getCompairsonValue().getClass());
        return String.format("%s is null or %s != %s", key, key, this.formatValue(filter.getCompairsonValue()));
    }

    private String mapGreaterThanFilter(GreaterThanFilter filter) {
        String key = this.formatKey(filter.getKey(), filter.getCompairsonValue().getClass());
        return String.format("%s > %s", key, this.formatValue(filter.getCompairsonValue()));
    }


    private String mapGreaterThanEqualFilter(GreaterThanEqualFilter filter) {
        String key = this.formatKey(filter.getKey(), filter.getCompairsonValue().getClass());
        return String.format("%s >= %s", key, this.formatValue(filter.getCompairsonValue()));
    }

    private String mapInFilter(InFilter filter) {
        return String.format("%s in %s", this.formatKeyAsString(filter.getKey()), this.formatValuesAsString(filter.getComparisonValues()));
    }

    private String mapNotInFilter(NotInFilter filter) {
        String key = this.formatKeyAsString(filter.getKey());
        return String.format("%s is null or %s not in %s", key, key, this.formatValuesAsString(filter.getComparisonValues()));
    }

    private String mapLessThanEqualFilter(LessThanEqualFilter filter) {
        String key = this.formatKey(filter.getKey(), filter.getCompairsonValue().getClass());
        return String.format("%s <= %s", key, this.formatValue(filter.getCompairsonValue()));
    }

    private String mapLessThanFilter(LessThanFilter filter) {
        String key = this.formatKey(filter.getKey(), filter.getCompairsonValue().getClass());
        return String.format("%s < %s", key, this.formatValue(filter.getCompairsonValue()));
    }

    private String mapLikeFilter(LikeFilter filter) {
        String key = this.formatKey(filter.getKey(), filter.getCompairsonValue().getClass());
        return String.format("%s is not null and %s ~ %s", key, key, this.formatValue(filter.getCompairsonValue()));
    }

    private String mapAndFilter(AndFilter filter) {
        return String.format(" %s and %s", this.map(filter.getLeft()), this.map(filter.getRight()));
    }

    private String mapOrFilter(OrFilter filter) {
        return String.format(" (%s or %s)", this.map(filter.getLeft()), this.map(filter.getRight()));
    }

    private String mapNotFilter(NotFilter filter) {
        return String.format(" not( %s)", this.map(filter.getExpression()));
    }

    private String formatValue(Object value) {
        return !(value instanceof String) && !(value instanceof UUID) ? value.toString() : "'" + String.valueOf(value) + "'";
    }

    abstract String formatKey(String key, Class<?> type);

    abstract String formatKeyAsString(String key);


    String formatValuesAsString(Collection<?> values) {
        if (values == null || values.isEmpty()) {
            return "('')";
        }
        return "(" + (String) values.stream().map((v) -> {
            return String.format("'%s'", v);
        }).collect(Collectors.joining(",")) + ")";
    }
}
